#include "Layout.h"

.code16
.section .inittext, "ax"
// We start at 0x0:BOOTMAIN.
.global boot_entry
boot_entry:
// collect BIOS data <([{
	cld

	push %ds
	ldsw (4 * 0x41), %si // hd0.
	movw $hd0_parameter_table, %di
	movw $0x10, %cx
	rep
	movsb
	pop %ds
	movw $0x1500, %ax // check if there's a hd1 or not.
	movb $0x81, %dl
	int $0x13
	jc 1f
	cmpb $0x3, %ah
	jne 1f
	push %ds
	ldsw (4 * 0x46), %si // hd1.
	movw $hd1_parameter_table, %di
	movw $0x10, %cx
	rep
	movsb
	pop %ds
1:
	movw $0x7dbe, %si // partition table.
	movw $harddisk_partition_table, %di
	movw $0x40, %cx
	rep
	movsb

	movw $0xe801, %ax // memory.
	int $0x15
	jc error
	shrw $2, %cx
	shlw $4, %dx
	addw %cx, %dx
	addw $0x100, %dx // lower 1M.
	movw %dx, (e801)

	movb $0xf, %ah // display.
	movw $display_parameter_table, %di
	int $0x10
	movw %bx, (%di)
	movw %ax, 2(%di)
	movb $0x12, %ah
	movb $0x10, %bl
	int $0x10
	movw %bx, 4(%di)
	movw %cx, 6(%di)
	addw $8, %di

	// keyboard.
	// 8259a.
	// a20 is opened by bochs by default, see bochs.source/config.h.
// }])>

// load the remain 54 sectors (zeroimage) <([{
	movw $0x80, %dx
	movw $0x000a, %cx
	movw $ZEROIMAGE_TEMPORARY, %bx
	movw $0x0236, %ax
	int $0x13
	jc error
// }])>

// load cxxfix.test.elf, cxxpic.test.elf, fix.elf and pic.elf into memory. <([{
#define ELF_SECTOR_COUNT			0x7e
	push %es

	movw $CXXFIX_TEST_ELF_DOS_ADDR >> 4, %ax
	movw %ax, %es
	movw $0x100 + 0x80, %dx
	movw $0x1, %cx
	movw $0x0, %bx
	movw $ELF_SECTOR_COUNT + 0x0200, %ax
	int $0x13
	jc error

	movw $CXXPIC_TEST_ELF_DOS_ADDR >> 4, %ax
	movw %ax, %es
	movw $0x300 + 0x80, %dx
	movw $0x1, %cx
	movw $0x0, %bx
	movw $ELF_SECTOR_COUNT + 0x0200, %ax
	int $0x13
	jc error

	movw $FIX_ELF_DOS_ADDR >> 4, %ax
	movw %ax, %es
	movw $0x500 + 0x80, %dx
	movw $0x1, %cx
	movw $0x0, %bx
	movw $ELF_SECTOR_COUNT + 0x0200, %ax
	int $0x13
	jc error

	movw $PIC_ELF_DOS_ADDR >> 4, %ax
	movw %ax, %es
	movw $0x700 + 0x80, %dx
	movw $0x1, %cx
	movw $0x0, %bx
	movw $ELF_SECTOR_COUNT + 0x0200, %ax
	int $0x13
	jc error

	pop %es
// }])>

	cli

// relocate zeroimage to ZEROIMAGE and initialize bss section. <([{
	movl $ZEROIMAGE_TEMPORARY, %esi
	movl $ZEROIMAGE, %edi
	movl $_zero_image, %edx
	movl $_zero_image_end, %ecx
	subl %edx, %ecx
	rep
	movsb

	// initialize bss section.
	movl $_zero_image_bss, %edi
	movl $_zero_image_bss_end, %ecx
	subl %edi, %ecx
	movl $0, %eax
	rep
	stosb
// }])>

// align _zero_image_end to page. <([{
	movl $_zero_image_end, %eax
	movl %eax, %ebx
	andl $0xfffff000, %ebx
	cmpl %ebx, %eax
	jz 1f
	addl $PAGE_SIZE, %ebx
1:
// }])>

// initialize the first page directory (cr3). <([{
	movl %ebx, (root_page_directory)
	movl %ebx, %edi
	movl $1024, %ecx
	movl $0, %eax
	rep
	stosl
	movl $0x183, (%ebx) // The first entry is the first 4M-page.
	movl %ebx, %cr3
	addl $PAGE_SIZE, %ebx
// }])>

// enter protect mode, (gdt, cr4, cr0 and all segment registers. <([{
	lgdt (gdt_addr)
	movl %cr4, %eax
	orl $0x10, %eax
	movl %eax, %cr4 // toggle PSE.
	movl %cr0, %eax
	orl $0x80000001, %eax
	movl %eax, %cr0 // page and protect mode are enabled together.
	ljmpl $PROTECT_MODE_CS, $1f
1:
.code32
	movw $PROTECT_MODE_DS, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %ss
// }])>

// allocate 2 pages for stack. <([{
	addl $PAGE_SIZE * 2, %ebx
	movl %ebx, %esp
	movl %ebx, (root_stack)
// }])>

	movl %ebx, (dosLowerBound)

	call boot_c_entry

error:
	jmp error

// vim: foldmarker=<([{,}])> foldmethod=marker
